function creatDom (params) {
    const h1 = document.createElement('h1')
    h1.innerHTML = '手写Promise'
    document.body.appendChild(h1)
}
creatDom()
/** 
 * 构造函数
 * 1. 定义类
 * 2. 添加构造函数
 * 3. 定义resolve、reject 
 * 4. 执行回调函数
 * 状态及原因
 * 5. 添加状态 pending fulfilled rejected
 * 6. 添加原因
 * 7. 调整 resolve reject
 * 8. 状态不可逆
 * then方法
 * 9. 添加实例方法  then 【参数判断： 执行成功回调、执行失败回调】
 * 10.定义私有实例属性
 * 11.保存回调函数
 * 12.调用成功、失败回调
 * 异步任务
 * 13. 定义异步函数 进行封装
 * 14. 调用核心api 【 queueMicrotask、MutationObserver、setTimeout】
 * 链式编程
 * 15. 返回Promise实例
 * 16. 返回值 【处理返回值；处理异常】
 * 17. 处理返回 Promise 调用then 方法
 * 18. 处理 循环引用问题
 * 19. 抽调函数
 * 20. 调用函数
 * 
 * catch方法
 * 21. 内部调用 then 方法
 * 22. 处理异常
 * 
 * finally方法
 * 22. 内部调用 then 方法
 * 23. 传入同一个回调函数
 * 
 * ========== 静态方法 ===========
 * 静态 resolve 方法
 * 24.判断传入值
 * 25.Promise直接返回
 * 26.转为Promise并返回（fulfilled）
 * 
 * 静态 reject 方法
 * 27.返回reject状态的promise
 * 
 * 静态 race 方法
 * 28. 返回 Promise
 * 29. 判断是否为迭代对象 错误信息：Argument is not iterable 
 * 30. 等待第一个敲定
 * 
 * 静态 all 方法
 * 31. 返回 Promise
 * 32. 判断是否为迭代对象 错误信息：Argument is not iterable
 * 33. 判断是否为空的可迭代对象 可直接被兑现
 * 34. 记录结果【保证promises 顺序和结果顺序一致；】
 * 35. 判断全部兑现 【通过次数判断 是否全部兑现（不能使用索引）】
 * 36. 处理第一个拒绝
 * 
 * 静态 allSettled 方法
 * 37. 传入Promise全部变成已敲定，即可获取兑现结果
 * 38. 结果数组：[{status: 'fulfilled', value: '111111'},{status: 'rejected', reason: 'error'}]
 * 39. 结果数组顺序和传入的Promise数组顺序一致
 * 40. 空数组，直接兑现
 * 
 * 静态 any 方法
 * 41.参数 promise数组
 * 42.结果 获取到第一个成功原因 或者 所有拒绝原因  AggregateError: All promises were rejected
 * 43.传入空数组 直接报错
 * 44.不传参数 直接报错
 * 
 * Promise A+ 测试
 * 核心步骤：
 * 1. 使用 commonJS 的模块化语法暴露出去
 *   1.1 提供 deferred 方法，返回对象{promise,resolve,reject}
 *   1.2 promise: pending状态的promise的实例
 *   1.2 resolve: 已传入的原因兑现promise
 *   1.2 reject: 已传入的原因拒绝promise
 * 2. 下包
 *   2.1 初始化项目 npm init -y
 *   2.2 npm i promises-aplus-tests -D （开发依赖）
 * 3. 配置 script：promises-aplus-tests 代码文件
 * 
*/

class MyPromise {
    #PENDING = 'pending'
    #FULFILLED = 'fulfilled'
    #REJECTED = 'rejected'
    state = this.#PENDING
    result = undefined
    // [{onFulfilled, onRejected}...]
    #handlers = []

    constructor(callback) {
        const resolve = (result) => {
            // 改状态 pending -> fulfilled
            // 记录原因 
            if (this.state !== this.#PENDING) return
            this.state = this.#FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
                onFulfilled(this.result)
            })
        }
        const reject = (result) => {
            // 改状态 pending -> rejected
            // 记录原因 
            if (this.state !== this.#PENDING) return
            this.state = this.#REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
                onRejected(this.result)
            })
        }
        try {
            callback(resolve, reject)
        } catch (error) {
            // 处理实例化时 callback 函数错误异常
            // console.log('')
            reject(error)
        }
    }
    #runAsynctask (callback) {
        if (typeof queueMicrotask === 'function') {
            queueMicrotask(callback)
        } else if (typeof MutationObserver === 'function') {
            const obs = new MutationObserver(callback)
            const divNode = document.createElement('div')
            obs.observe(divNode, { childList: true })
        } else if (typeof setTimeout === 'function') {
            setTimeout(callback, 0)
        }
    }
    #publicFunction (result, newPromise, resolve, reject) {
        // 处理重复引用
        if (newPromise === result) {
            // console.log('重复引用le,返回的是P2')
            // 抛出错误
            throw new TypeError('Chaining cycle detected for promise #<Promise>')
        }

        // 判断处理返回 Promise
        if (result instanceof MyPromise) {
            console.log('MyPromise实例')
            // 调用then方法 获取 x 的resolve或者reject的结果
            result.then(res => {
                // console.log(res)
                resolve(res)
            }, rej => {
                // console.log(rej)
                reject(rej)
            })
        } else {
            resolve(result)
        }
    }
    then (onFulfilled, onRejected) {
        // 【参数判断： 执行成功回调、执行失败回调】
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
        const newPromise = new MyPromise((resolve, reject) => {
            if (this.state === this.#FULFILLED) {
                this.#runAsynctask(() => {
                    try {
                        const x = onFulfilled(this.result)
                        // // 处理重复引用
                        // if (newPromise === x) {
                        //     // console.log('重复引用le,返回的是P2')
                        //     // 抛出错误
                        //     throw new TypeError('Chaining cycle detected for promise #<Promise>')
                        // }

                        // // 判断处理返回 Promise
                        // if (x instanceof MyPromise) {
                        //     console.log('MyPromise实例')
                        //     // 调用then方法 获取 x 的resolve或者reject的结果
                        //     x.then(res => {
                        //         // console.log(res)
                        //         resolve(res)
                        //     }, rej => {
                        //         // console.log(rej)
                        //         reject(rej)
                        //     })
                        // } else {
                        //     resolve(x)
                        // }

                        this.#publicFunction(x, newPromise, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            } else if (this.state === this.#REJECTED) {
                this.#runAsynctask(() => {
                    try {
                        const x = onRejected(this.result)
                        this.#publicFunction(x, newPromise, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            } else if (this.state === this.#PENDING) {
                this.#handlers.push({
                    onFulfilled: (result) => {
                        this.#runAsynctask(() => {
                            try {
                                const x = onFulfilled(result)
                                this.#publicFunction(x, newPromise, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }

                        })
                    },
                    onRejected: (result) => {
                        this.#runAsynctask(() => {
                            try {
                                const x = onRejected(result)
                                this.#publicFunction(x, newPromise, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                    }
                })
            }
        })

        return newPromise
    }
    catch (onRejected) {
        // 内部调用then方法
        return this.then(undefined, onRejected)
    }
    fainlly (onFianlly) {
        return this.then(onFianlly, onFianlly)
    }
    static resolve (value) {
        if (value instanceof MyPromise) return value
        // return new MyPromise((res, rej) => {
        return new MyPromise(res => {
            res(value)
        })

    }
    static reject (value) {
        return new MyPromise((res, rej) => {
            rej(value)
        })
    }
    static race (value) {
        return new MyPromise((resolve, reject) => {
            const isIterable = value => value != null && typeof value[Symbol.iterator] === 'function'
            if (isIterable(value)) {
                for (const iterator of value) {
                    // value 可能不是一个 promise 实例需要使用 resolve转为promise 实例
                    MyPromise.resolve(iterator).then(res => {
                        resolve(res)
                    }, rej => {
                        reject(rej)
                    })
                }

            } else {
                const type = Object.prototype.toString.call(value).slice(8, -1)
                reject(new TypeError(`${type === value ? value : type + ' ' + value} is not iterable (cannot read property Symbol(Symbol.iterator))`))
            }
        })
    }
    static all (value) {
        return new MyPromise((resolve, reject) => {
            const isIterable = value => value != null && typeof value[Symbol.iterator] === 'function'
            // / 记录结果 保持结果的顺序位置跟传入一至 需要使用数组索引赋值
            const list = []
            const results = []
            let index = 0
            let count = 0
            if (isIterable(value)) {
                for (const iterator of value) {
                    list.push({
                        index: index++,
                        value: iterator
                    })
                }
                const arr = list.filter(item => item.value)
                if (arr.length <= 0) {
                    resolve(value)
                } else {
                    // 记录结果 保持结果的顺序位置跟传入一至 需要使用数组索引赋值
                    // 判断是否全部兑现，记录兑现次数如果全部兑现，传出兑现结果
                    list.forEach(({ value, index }) => {
                        MyPromise.resolve(value).then(
                            res => {
                                results[index] = res
                                // 判断是否全部兑现
                                count++
                                count === list.length && resolve(results)
                            }, rej => {
                                reject(rej)
                            }
                        )
                    })
                }

            } else {
                const type = Object.prototype.toString.call(value).slice(8, -1)
                reject(new TypeError(`${type === value ? value : type + ' ' + value} is not iterable (cannot read property Symbol(Symbol.iterator))`))
            }
        })
    }
    static allSettled (value) {
        const that = this
        console.log('that', this.REJECTED, that, this)
        return new MyPromise((resolve, reject) => {
            const isIterable = value => value != null && typeof value[Symbol.iterator] === 'function'
            // / 记录结果 保持结果的顺序位置跟传入一至 需要使用数组索引赋值
            const list = []
            const results = []
            let index = 0
            let count = 0
            if (isIterable(value)) {
                for (const iterator of value) {
                    list.push({
                        index: index++,
                        value: iterator
                    })
                }
                const arr = list.filter(item => item.value)
                if (arr <= 0) {
                    resolve(value)
                } else {
                    // 记录结果 保持结果的顺序位置跟传入一至 需要使用数组索引赋值
                    // 判断是否全部兑现，记录兑现次数如果全部兑现，传出兑现结果
                    list.forEach(({ value, index }) => {
                        MyPromise.resolve(value).then(
                            res => {
                                results[index] = {
                                    status: 'fulfilled',
                                    value: res,
                                }
                                // 判断是否全部兑现
                                count++
                                count === list.length && resolve(results)
                            }, rej => {
                                results[index] = {
                                    status: 'rejected',
                                    value: rej,
                                }
                                // 判断是否全部兑现
                                count++
                                count === list.length && resolve(results)
                            }
                        )
                    })
                }

            } else {
                const type = Object.prototype.toString.call(value).slice(8, -1)
                reject(new TypeError(`${type === value ? value : type + ' ' + value} is not iterable (cannot read property Symbol(Symbol.iterator))`))
            }
        })
    }
    static any (value) {
        return new MyPromise((resolve, reject) => {
            const isIterable = value => value != null && typeof value[Symbol.iterator] === 'function'
            // / 记录结果 保持结果的顺序位置跟传入一至 需要使用数组索引赋值
            const list = []
            const results = []
            let index = 0
            let count = 0
            if (isIterable(value)) {
                for (const iterator of value) {
                    list.push({
                        index: index++,
                        value: iterator
                    })
                }
                const arr = list.filter(item => item.value)
                if (arr.length <= 0) {
                    // 判断是不是空可迭代对象 如果是直接拒绝
                    return reject(new AggregateError(value, 'All promises were rejected'))
                } else {
                    // 等待结果
                    list.forEach(({ value, index }) => {
                        MyPromise.resolve(value).then(res => {
                            resolve(res)
                        }, rej => {
                            results[index] = rej
                            // 判断是否全部兑现
                            count++
                            count === list.length && reject(new AggregateError(results, 'All promises were rejected'))
                        })
                    })
                }

            } else {
                const type = Object.prototype.toString.call(value).slice(8, -1)
                reject(new TypeError(`${type === value ? value : type + ' ' + value} is not iterable (cannot read property Symbol(Symbol.iterator))`))
            }
        })
    }
}

// function runAsynctask (callback) {
//     if (typeof queueMicrotask === 'function') {
//         queueMicrotask(callback)
//     } else if (typeof MutationObserver === 'function') {
//         const obs = new MutationObserver(callback)
//         const divNode = document.createElement('div')
//         obs.observe(divNode, { childList: true })
//     } else if (typeof setTimeout === 'function') {
//         setTimeout(callback, 0)
//     }
// }
// console.log(111)
// runAsynctask(() => {
//     console.log('runAsynctask', runAsynctask)
// })
// console.log(222)
//================= 测试代码 ==================
// const p = new MyPromise((resolve, reject) => {
//     console.log('执行了')
//     setTimeout(() => {
//         // reject('error1234')

//         resolve('success')
//     }, 2000)
// })
// console.log('@@@!@@1111')
// const p = new MyPromise((resolve, reject) => {
//     console.log('执行了')
//     // reject('error1234')

//     resolve('success')
// })
// console.log(p)
// p.then(res => {
//     console.log('p1', res)
//     throw 'throw-error'
//     // return 22222
// }, rej => {
//     console.log('p1-error', rej)
// }).then(res => {
//     console.log('p2', res)
// }, rej => {
//     console.log('p2-error', rej)
// })
// // p.then(res => {
// //     console.log('成功回调', res)
// // },)
// console.log('@@!@@2222')

// === 原生 promise 处理循环引用问题
// const p = new Promise((resolve, reject) => {
//     resolve(';1')
// })
// const p2 = p.then(res => {
//     return p2
// })
// p2.then(res => {
//     console.log('p2:', res)
// }, rej => {
//     console.log('p2:', rej)
// })

// const p = new MyPromise((resolve, reject) => {
//     // resolve('resolve:error')
//     // reject('reject:error')
//     throw 'error'
// })
// p.then(res => {
//     console.log('res;', res)
// },).catch(e => {
//     console.log('catch,eee', e)
// }).fainlly(() => {
//     console.log('finally')
// })




// const pp = new Promise((res, rej) => {
//     setTimeout(() => {
//         throw 12345678
//     }, 2000)
// })
// pp.then(res => {
//     console.log('res;', res)
// },).catch(e => {
//     console.log('catch,eee', e)
// })

// MyPromise.resolve(new MyPromise((resolve, reject) => {
//     resolve('resolve')
//     reject('reject')
//     throw 'error'
// })).then(res => {
//     console.log('res:', res)
// }).catch(e => {
//     console.log('rej:', e)
// })

// MyPromise.reject('66998800').then(res => {
//     console.log('res:', res)
// }).catch(e => {
//     console.log('rej:', e)
// })
// Promise.race('81111').then(res => {
//     console.log('res', res)
// }).catch(e => {
//     console.log('eee', e)
// })
// const p1 = MyPromise.resolve('111111')
// const p2 = new MyPromise((res, rej) => {
//     setTimeout(() => {
//         // res('222222')
//         rej('error')
//     }, 1000)
// })
// const p3 = 'p3333333333'
// MyPromise.race('111').then(res => {
//     console.log('res:', res)
// }).catch(e => {
//     console.log('eeeee:', e)
// })

// MyPromise.all([p1, p2, p3]).then(res => {
//     console.log('res:', res)
// }).catch(e => {
//     console.log('eeeee:', e)
// })

/** 
 * Promise.allSettled
 * 1. 传入Promise全部变成已敲定，即可获取兑现结果
 * 2. 结果数组：[{status: 'fulfilled', value: '111111'},{status: 'rejected', reason: 'error'}]
 * 3. 结果数组顺序和传入的Promise数组顺序一致
 * 4. 空数组，直接兑现
 * */

// Promise.allSettled([p1, p2, p3]).then(res => {
//     console.log(res)
// }, rej => {
//     console.log(rej)
// })
// MyPromise.allSettled([p1, p2, p3]).then(res => {
//     console.log(res)
// }, rej => {
//     console.log(rej)
// })

const p1 = MyPromise.reject('111111')
const p2 = new MyPromise((res, rej) => {
    setTimeout(() => {
        // res('222222')
        rej('error')
    }, 1000)
})
const p3 = 'p3333333333'
MyPromise.any([p1, p2]).then(res => {
    console.log(res)
}, rej => {
    console.dir(rej)
})


//============= 异步任务 * queueMicrotask ==============
// console.log('11111')
// queueMicrotask(() => {
//     console.log('queueMicrotask')
// })
// console.log('6666')
//============= 异步任务 * MutationObserver ==============
/**
 * 创建观察器，传入回调函数
 * 创建元素，添加监听
 * 修改元素内容
 */
// const ops = new MutationObserver(() => {
//     console.log('new MutationObserver')
// })
// console.log('111111')
// const div = document.createElement('div')
// // 参数1： 观察的 dom 节点
// // 参数2： 观察的选项（childList 观察子节点改变）
// ops.observe(div, { childList: true })
// div.innerHTML = '测试MutationObserver'
// console.log('22222222')
//============= 异步任务 * setTimeout ============== 
module.export = {
    deferred () {
        const res = {}
        res.promise = new MyPromise((resolve, reject) => {
            res.resolve = resolve
            res.reject = reject
        })
        return res
    }
}
